package com.easylinkin.linkappapi.lobar.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.deviceservice.service.DeviceServiceService;
import com.easylinkin.linkappapi.lobar.dto.excel.ExcelResultDTO;
import com.easylinkin.linkappapi.lobar.dto.excel.ExcelResultDetailDTO;
import com.easylinkin.linkappapi.lobar.dto.gate.UpGateDTO;
import com.easylinkin.linkappapi.lobar.entity.EnUserGateLink;
import com.easylinkin.linkappapi.lobar.entity.Gate;
import com.easylinkin.linkappapi.lobar.mapper.EnUserGateLinkMapper;
import com.easylinkin.linkappapi.lobar.mapper.GateMapper;
import com.easylinkin.linkappapi.lobar.service.EnUserGateLinkService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.openapi.dto.ApiDownResultDTO;
import com.easylinkin.linkappapi.openapi.service.OpenApiService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * <p>
 * 管理人员闸机关联表 服务实现类
 * </p>
 *
 * @author TongJie
 * @since 2022-04-13
 */
@Service
public class EnUserGateLinkServiceImpl extends ServiceImpl<EnUserGateLinkMapper, EnUserGateLink> implements EnUserGateLinkService {

  @Resource
  private LinkappUserContextProducer linkappUserContextProducer;
  @Autowired
  private GateMapper gateMapper;
  @Autowired
  private DeviceMapper deviceMapper;
  @Autowired
  private DeviceServiceService deviceServiceService;
  @Autowired
  private OpenApiService openApiService;
  @Autowired
  private RedisTemplate redisTemplate;
  @Autowired
  private RestTemplate restTemplate;
  @Value("${edu.apiUrl}")
  private String eduApiUrl;

  /**
   * 增加
   * @param enUserGateLink
   */
  @Override
  public void insert(EnUserGateLink enUserGateLink) {
    /**
     * 验证重复
     */
    this.checkExist(enUserGateLink);
    //设置基本属性
    this.setBase(enUserGateLink);
    this.save(enUserGateLink);
  }

  /**
   * 根据id编辑
   * @param enUserGateLink
   */
  @Override
  public void updateOne(EnUserGateLink enUserGateLink) {
    /**
     * 验证重复
     */
    this.checkExist(enUserGateLink);
    //设置基本属性
    this.setBase(enUserGateLink);
    this.updateById(enUserGateLink);
  }

  /**
   * 人员同步闸机
   * @param jsonObjectList
   */
  @Override
  public void syncUser(List<JSONObject> jsonObjectList) {
    //查找需要同步的闸机
    QueryWrapper<Gate> queryWrapper = new QueryWrapper<>();
    queryWrapper.isNotNull("code_").like("access_",1);
    List<Gate> gates = gateMapper.selectList(queryWrapper);
    Set<String> codeSet = gates.stream().map(g -> g.getCode()).collect(Collectors.toSet());
    if (null != codeSet && codeSet.size()>0) {
      //查询在不在设备库里
      List<Device> devices = deviceMapper.findDeviceByCodesGlobal(codeSet, null);
      Set<String> codes = devices.stream().map(g -> g.getCode()).collect(Collectors.toSet());
      if (null == codes || codes.size() < 1) {
        throw new BusinessException("没有绑定到真实设备的闸机");
      }else {
        //组织下发
        jsonObjectList.removeIf(json -> StringUtils.isBlank(json.getString("photo")));
        if (jsonObjectList.size() < 1){
          throw new BusinessException("没有符合条件的下发用户");
        }
        codeSet.forEach(code ->{
          //查询该闸机已经下发过的数据
          List<Gate> gateList = gates.stream().filter(gate -> code.equals(gate.getCode()))
              .collect(Collectors.toList());
          if (gateList.size() > 0){
            Gate gate = gateList.get(0);
            QueryWrapper<EnUserGateLink> linkQueryWrapper = new QueryWrapper<>();
            linkQueryWrapper.eq("gate_id_",gate.getId());
            List<EnUserGateLink> enUserGateLinks = baseMapper.selectList(linkQueryWrapper);
            List<Long> ids = enUserGateLinks.stream().map(e -> e.getUserId())
                .collect(Collectors.toList());
            //排除掉已经下发的
            List<JSONObject> jsonObjects = jsonObjectList.stream()
                .filter(json -> !ids.contains(json.getLong("id")))
                .collect(Collectors.toList());
            if (jsonObjects.size() > 0){
              jsonObjects.forEach(user ->{
                EnUserGateLink enUserGateLink = new EnUserGateLink();
                enUserGateLink.setModifyTime(new Date());
                enUserGateLink.setCreateTime(new Date());
                enUserGateLink.setTenantId(gate.getTenantId());
                enUserGateLink.setGateId(gate.getId());
                enUserGateLink.setUserId(user.getLong("id"));
                enUserGateLink.setPhoto(user.getString("photo"));
                enUserGateLink.setCard(user.getString("idCard"));
                enUserGateLink.setTelephone(user.getString("telephone"));
                enUserGateLink.setOrganizationId(user.getLong("organizationId"));
                enUserGateLink.setOrganizationName(user.getString("organizationName"));
                enUserGateLink.setUserName(user.getString("name"));
                baseMapper.insert(enUserGateLink);

                //后更新
                Map<String, Object> downParameter = new HashMap<>();
                //设备编号
                downParameter.put("device_id",gate.getCode());
                Map<String, Object> parameter = new HashMap<>();
                //id要生成 定义id
                String idPre = EnUserGateLink.getIdPre();
                parameter.put("id",idPre+enUserGateLink.getId());
                parameter.put("idCard",enUserGateLink.getCard());
                parameter.put("name",enUserGateLink.getUserName());
                parameter.put("role",1);
                parameter.put("regImage",enUserGateLink.getPhoto());
                downParameter.put("parameter",parameter);
                downParameter.put("service_id","uploadPerson");
                ApiDownResultDTO send = deviceServiceService.send(downParameter);
                if (!"0".equals(send.getCode())){
                  //失败了要删除保存的关系
                  baseMapper.deleteById(enUserGateLink.getId());
                }
              });
            }
          }
        });
      }
    }
  }

  /**
   * 同步授权人员
   * @param gate
   */
  @Override
  public void upUserToGate(String id) {
    //查询闸机
    Gate gate = gateMapper.selectById(id);
    String code = gate.getCode();
    if (StringUtils.isBlank(code)){
      throw new BusinessException("闸机没有填写序列号");
    }else {
      //查询真实设备
      //查询在不在设备库里
      Set<String> codes = new HashSet<>();
      codes.add(code);
      List<Device> devices = deviceMapper.findDeviceByCodesGlobal(codes,gate.getTenantId());
      if (devices.size() < 1){
        throw new BusinessException("闸机没有绑定到真实设备");
      }
    }
    if (StringUtils.isBlank(gate.getAccess()) || !gate.getAccess().contains("1")){
      throw new BusinessException("闸机没有施工云通行权限");
    }
    getResultDTO(gate);
  }

  /**
   * @param gate
   * @return
   */
  private ExcelResultDTO getResultDTO(Gate gate){
    ExcelResultDTO excelResultDTO = new ExcelResultDTO();
    //向企业级请求需要同步的人员数据
    List<Map<String, Object>> mapList = restTemplate
        .getForObject(eduApiUrl + "/enterprise/user/getEnUser", List.class);
    if (mapList.size() < 1){
      throw new BusinessException("没有需要同步的人员");
    }
    //查询改闸机已经下发的人员信息
    QueryWrapper<EnUserGateLink> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("gate_id_",gate.getId())
        .eq("tenant_id_",linkappUserContextProducer.getNotNullCurrent().getTenantId());
    List<EnUserGateLink> enUserGateLinks = baseMapper.selectList(queryWrapper);
    List<Long> userIds = enUserGateLinks.stream().map(e -> e.getUserId())
        .collect(Collectors.toList());
    List<Map<String, Object>> mapList1 = mapList.stream().filter(map -> !userIds.contains(map.get("id")))
        .collect(Collectors.toList());
    if (mapList1.size() < 1){
      throw new BusinessException("没有需要同步的人员");
    }
    //另起一个线程处理下发
    setToRedis(gate.getId(),null);
    List<Map<String, Object>> finalMapList = mapList1;
    new Thread(() ->{
      try {
        excelResultDTO.setSum(finalMapList.size());
        List<ExcelResultDetailDTO> sonList = new ArrayList<>();
        finalMapList.forEach(e -> {
          System.out.println(e);
          JSONObject json = new JSONObject(e);
          ExcelResultDetailDTO detailDTO = userToOneGate(json, gate);
          if (Integer.valueOf(1).equals(detailDTO.getType())){
            sonList.add(detailDTO);
          }
        });
        excelResultDTO.setExcelResultDetailDTOS(sonList);
        excelResultDTO.setFail(sonList.size());
        excelResultDTO.setSuccess(excelResultDTO.getSum()-sonList.size());
        //得到的结果存放redis
        setToRedis(gate.getId(),excelResultDTO);
      } catch (Exception e) {
        //异常也要保存结果
        setToRedis(gate.getId(),excelResultDTO);
      }
    }).start();
    return excelResultDTO;
  }

  /**
   * 下发到指定闸机
   * @param gate
   * @param jsonObject
   * @return
   */
  private ExcelResultDetailDTO userToOneGate(JSONObject jsonObject, Gate gate) {
    ExcelResultDetailDTO excelResultDetailDTO = new ExcelResultDetailDTO();
    excelResultDetailDTO.setTypeName(jsonObject.getString("idCard")+"/"+jsonObject.getString("telephone"));
    if (StringUtils.isBlank(jsonObject.getString("photo"))){
      excelResultDetailDTO.setType(1);
      excelResultDetailDTO.setName(jsonObject.getString("name"));
      excelResultDetailDTO.setDetail("没有近期照片");
      excelResultDetailDTO.setObj(jsonObject);
      return excelResultDetailDTO;
    }

    EnUserGateLink enUserGateLink = new EnUserGateLink();
    //先查询有没有下发过
    QueryWrapper<EnUserGateLink> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("tenant_id_",gate.getTenantId())
        .eq("gate_id_",gate.getId())
        .eq("user_id_",jsonObject.getLong("id"));
    List<EnUserGateLink> enUserGateLinks = baseMapper.selectList(queryWrapper);
    if (enUserGateLinks.size()>0){
      excelResultDetailDTO.setType(1);
      excelResultDetailDTO.setName(jsonObject.getString("name"));
      excelResultDetailDTO.setObj(jsonObject);
      excelResultDetailDTO.setDetail("下发闸机失败,该人员已经下发");
      return excelResultDetailDTO;
    }else {
      enUserGateLink.setModifyTime(new Date());
      enUserGateLink.setCreateTime(new Date());
      enUserGateLink.setTenantId(gate.getTenantId());
      enUserGateLink.setGateId(gate.getId());
      enUserGateLink.setUserId(jsonObject.getLong("id"));
      enUserGateLink.setPhoto(jsonObject.getString("photo"));
      enUserGateLink.setCard(jsonObject.getString("idCard"));
      enUserGateLink.setTelephone(jsonObject.getString("telephone"));
      enUserGateLink.setOrganizationId(jsonObject.getLong("organizationId"));
      enUserGateLink.setOrganizationName(jsonObject.getString("organizationName"));
      enUserGateLink.setUserName(jsonObject.getString("name"));
      baseMapper.insert(enUserGateLink);
    }

    //后更新
    Map<String, Object> downParameter = new HashMap<>();
    //设备编号
    downParameter.put("device_id",gate.getCode());
    Map<String, Object> parameter = new HashMap<>();
    //id要生成 定义id
    String idPre = EnUserGateLink.getIdPre();
    parameter.put("id",idPre+enUserGateLink.getId());
    parameter.put("idCard",enUserGateLink.getCard());
    parameter.put("name",enUserGateLink.getUserName());
    parameter.put("role",1);
    parameter.put("regImage",enUserGateLink.getPhoto());
    downParameter.put("parameter",parameter);
    downParameter.put("service_id","uploadPerson");
    ApiDownResultDTO send = deviceServiceService.send(downParameter);
    if (!"0".equals(send.getCode())){
      excelResultDetailDTO.setType(1);
      excelResultDetailDTO.setName(enUserGateLink.getUserName());
      excelResultDetailDTO.setObj(jsonObject);
      String s = "下发闸机失败";
      if (StringUtils.isNotBlank(send.getMsg())){
        s+= ": "+send.getMsg();
      }
      excelResultDetailDTO.setDetail(s);
      //失败了要删除保存的关系
      baseMapper.deleteById(enUserGateLink.getId());
    }else {
      excelResultDetailDTO.setType(6);
    }
    return excelResultDetailDTO;
  }

  /**
   * 开始下发时存一个初始结果到redis
   * @param gateId
   */
  private void setToRedis(String gateId,ExcelResultDTO excelResultDTO) {
    UpGateDTO upGateDTO = (UpGateDTO)redisTemplate.opsForValue().get(EnUserGateLink.getRedisIdPre()+gateId);
    if (null == upGateDTO){
      upGateDTO = new UpGateDTO();
    }
    if (null != excelResultDTO){
      upGateDTO.setUpTime(new Date());
      upGateDTO.setDone(true);
    }else {
      upGateDTO.setDone(false);
    }
    upGateDTO.setExcelResultDTO(excelResultDTO);
    redisTemplate.opsForValue().set(EnUserGateLink.getRedisIdPre()+gateId,upGateDTO);
  }

  @Override
  public IPage<EnUserGateLink> queryListByPage(RequestModel<EnUserGateLink> requestModel) {
    Page page = requestModel.getPage();
    EnUserGateLink enUserGateLink = requestModel.getCustomQueryParams();
    //项目id 过滤
    enUserGateLink.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
    IPage<EnUserGateLink> enUserGateLinkIPage = baseMapper.queryListByPage(page, enUserGateLink);
    return enUserGateLinkIPage;
  }

  /**
   * 验证重复
   */
  private void checkExist(EnUserGateLink enUserGateLink) {
    QueryWrapper<EnUserGateLink> queryWrapper = new QueryWrapper<>();
    //todo 设置判断重复条件
    //编辑的时候存在id
    Optional.ofNullable(enUserGateLink.getId()).ifPresent(id -> queryWrapper.ne("id",enUserGateLink.getId()));
    Integer integer = baseMapper.selectCount(queryWrapper);
    if (integer>0){
      throw new BusinessException("该管理人员闸机关联已存在");
    }
  }

  /**
   * 设置基本属性
   * @param enUserGateLink
   */
  private void setBase(EnUserGateLink enUserGateLink) {
    enUserGateLink.setModifyTime(new Date());
    //没有id就是新增,有就是编辑
    if (null == enUserGateLink.getId()){
      enUserGateLink.setCreateTime(new Date());
      if(StringUtils.isBlank(enUserGateLink.getTenantId())){
        enUserGateLink.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
      }
    }
  }
}
